#pragma once

#include <memory>
#include <assert.h>
#include <gtl/smart_ptr/deleter.h>

namespace gtl
{

template<class T, class Deleter = deleter::object>
class ptr
{
private:
	typedef ptr<T, Deleter> self_type;

public:
	typedef T element_type;
	typedef T value_type;
	typedef T* pointer;

public:
	ptr() : m_ptr(NULL)
	{
	}

	ptr(T* p) : m_ptr(p)
	{
	}

	~ptr()
	{
		release();
	}

private:
	ptr(const self_type& r);
	ptr& operator=(const self_type& r);

public:
	ptr& operator=(T* p)
	{
		release();
		m_ptr = p;
		return *this;
	}

	ptr& operator=(int null) throw(...)
	{
		if(null != 0)
			throw 0;

		release();
		m_ptr = 0;
		return *this;
	}

	T* detach()
	{
		T* p = m_ptr;
		m_ptr = NULL;
		return p;
	}

	T* get() const
	{
		return m_ptr;
	}

	void swap(self_type& r)
	{
		std::swap(m_ptr, other.m_ptr);
	}

	void reset()
	{
		self_type().swap(*this);
	}

	void reset(T* p)
	{
		if(p == m_ptr)
			return;

		self_type(p).swap(*this);
	}

	T& operator*() const
	{
		assert(m_ptr != NULL);
		return *m_ptr;
	}

	operator T*() const
	{
		return m_ptr;
	}

	operator T*&()
	{
		return m_ptr;
	}

	T** operator&()
	{
		return &m_ptr;
	}

	T** operator&() const
	{
		return &m_ptr;
	}

	T* operator->() const
	{
		assert(m_ptr != NULL);
		return m_ptr;
	}

public:
	virtual void release()
	{
		if(m_ptr == NULL)
			return;

		Deleter()(m_ptr);
		m_ptr = NULL;
	}

protected:
	T* m_ptr;
};

} // end of namespace gtl